//
// Created by Administrator on 2025-06-19.
//

#pragma once

class Chunk
{

struct FreeBlock
{
    size_t offset;
    size_t size;
};

public:
    explicit Chunk(size_t capacity)
            : capacity_(capacity), used_(0)
    {
        data_ = new char[capacity_];
        freeBlocks_.push_back({0, capacity_});
    }

    ~Chunk()
    {
        delete[] data_;
    }

    void *allocate(size_t size)
    {
        for(auto it = freeBlocks_.begin(); it != freeBlocks_.end(); ++it)
        {
            if (it->size >= size)
            {
                size_t offset = it->offset;
                if (it->size > size)
                {
                    it->offset += size;
                    it->size -= size;
                }
                else
                {
                    freeBlocks_.erase(it);
                }
                used_ += size;
                return data_ + offset;
            }
        }
        return nullptr;
    }

    bool deallocate(void *ptr, size_t size)
    {
        if (!contains(ptr)) return false;
        size_t offset = static_cast<char *>(ptr) - data_;
        freeBlocks_.push_back({offset, size});
        used_ -= size;
        mergeFreeBlocks();
        return true;
    }

    bool contains(void *ptr) const
    {
        return ptr >= data_ && ptr < (data_ + capacity_);
    }

    bool isEmpty() const
    {
        return used_ == 0;
    }

private:

    void mergeFreeBlocks()
    {
        freeBlocks_.sort([](const FreeBlock &a, const FreeBlock &b)
                         {
                             return a.offset < b.offset;
                         });
        for(auto it = freeBlocks_.begin(); it != freeBlocks_.end();)
        {
            auto next = std::next(it);
            if (next != freeBlocks_.end() &&
                it->offset + it->size == next->offset)
            {
                it->size += next->size;
                freeBlocks_.erase(next);
            }
            else
            {
                ++it;
            }
        }
    }

    char *data_;
    size_t capacity_;
    size_t used_;
    std::list <FreeBlock> freeBlocks_;
};


